home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PsL Monthly 1993 December
/
PSL Monthly Shareware CD-ROM (December 1993).iso
/
prgmming
/
dos
/
c
/
stdlib1.exe
/
lha
/
MEMORY.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-07-10
|
24KB
|
841 lines
extrn PSP:word
stdlib segment para public 'slcode'
assume cs:stdlib
;
; Memory allocation routines: MemInit, malloc, and free.
;
;
; Local variables:
;
StartOfHeap dw ?
SizeOfHeap dw ?
FreeSpace dw ?
;
; Memory manager data structure:
;
mmstruct struc
blksize dw ?
bwdptr dw ?
fwdptr dw ?
refcnt dw ?
freebwdptr dw ? ;Only if in the free list.
freefwdptr dw ? ;Only if in the free list.
ends
;
; When using es and ds as pointers into the heap, the following equates
; come in handy.
;
esptr equ word ptr es:[0]
dsptr equ word ptr ds:[0]
;
NIL equ 0
;
;
; MemInit- Initializes the memory manager.
;
; On entry- DX contains the number of paragraphs of memory to reserve
; for other programs. The default (in shell.asm) is 0. If
; you intend to execute other programs from the program you're
; writing, you will have to reserve an appropriate amount of
; space for that program. If you attempt to reserve too
; much space, then this code splits the available free memory
; in half and gives half to the heap and reserves half for
; other programs. If this is desirable, simply set DX to
; 0ffffh before calling MemInit.
;
; On Exit- No error if carry is clear. In such a case, CX contains
; the number of paragraphs of memory actually allocated.
; AX contains the starting segment address of the free
; memory block.
;
; If carry is set, then an error occurred, AX contains the
; error code (DOS).
;
; WARNING: for this routine to work properly, the calling program has to
; declare (and initialize) a word variable by the name PSP which contains
; the program's program segment prefix value. Furthermore, the last segment
; in the program must be "zzzzzzseg" and this guy should NOT contain any
; valid data.
;
public sl_MemInit
sl_MemInit proc far
push bx
push dx
push es
;
; Compute program size, in paragraphs:
;
mov ax, seg PSP
mov es, ax
mov bx, es:PSP
mov es, bx
mov ax, seg zzzzzzseg
sub ax, bx
inc bx ;Safety margin
inc bx
mov ah, 4ah ;Memory block resize opcode
int 21h
;
; Now ask for a ridiculous amount of memory so we can find out how much is
; available.
;
mov bx, 0ffffh
mov ah, 48h ;Alloc block opcode
int 21h
;
;
; Allocate storage for the heap.
;
cmp bx, dx ;See if DX is too large.
ja GoodHeap
shr bx, 1 ;Use half remaining space.
jmp short SetNewAlloc
;
GoodHeap: sub bx, dx ;Make room for other apps.
SetNewAlloc: cmp bx, 10h ;Make sure there is some room.
jbe ErrorAlloc2
mov ah, 48h ;Alloc block opcode
int 21h
jc ErrorAlloc ;Shouldn't happen, but...
;
; Okay, we've just allocated the block, now set up our own local variables
; so we can keep track of the data.
;
mov cs:StartOfHeap, ax ;Save pointer to memory.
mov cs:FreeSpace, ax ;Save pointer to 1st free blk.
mov cs:SizeOfHeap, bx ;Size of heap in paragraphs.
mov es, ax ;Init pointer to heap.
xor ax, ax
mov esptr.blksize, bx ;Size of this block (paras).
mov esptr.bwdptr, ax ;Back pointer is NIL.
mov esptr.fwdptr, ax ;Fwd pointer is NIL.
mov esptr.refcnt, ax ;Reference Count is zero.
mov esptr.freebwdptr, ax ;Free list bwd ptr is NIL.
mov esptr.freefwdptr, ax ;Free list fwd ptr is NIL.
mov cx, bx ;Return size in CX
mov ax, cs:StartOfHeap
clc
jmp MemInitDone
;
ErrorAlloc2: mov ax, 8 ;Insufficient memory error.
ErrorAlloc: stc
MemInitDone: pop es
pop dx
pop bx
ret
sl_MemInit endp
;
;
;
;
;============================================================================
;
; * * * * * ***** *****
; ** ** * * * * * * * *
; * * * * * * * * * * *
; * * * ***** * * * * *
; * * * * * * * * *
; * * * * * * * * * *
; * * * * ***** ***** ***** *****
;
;============================================================================
;
;
; malloc- On entry, CX contains a byte count. Malloc allocates a block
; of storage of the given size and returns a pointer to this block
; in ES:DI. The value in ES:DI is always normalized, so you can
; compare pointers allocated via malloc as 32-bit values. Note
; that malloc always allocates memory in paragraph chunks.
; Therefore, this routine returns the actual number of bytes of
; memory allocated in the CX register (this may be as much as 15
; greater than the actual number asked for).
;
; Malloc returns carry clear if it allocated the storage without
; error. It returns carry set if it could not find a block large
; enough to satisfy the request.
;
;
; Data structure for memory allocation blocks:
;
; offset:
;
; 0 Size of Blk
; 2 Back link
; 4 Fwd Link
; 6 Reference Count
; 8 Data, if this block is allocated, prev link if on free list.
; 10 Data, if this block is allocated, next link if on free list.
;
;
;
public sl_malloc
sl_malloc proc far
push ax
push si
push ds
;
; Convert byte count to paragraph count, since we always allocate whole
; paragraphs.
;
add cx, 8 ;We have six bytes of overhead!
rcr cx, 1 ;Use rcr because of add above.
adc cx, 0
shr cx, 1
adc cx, 0
shr cx, 1
adc cx, 0
shr cx, 1
adc cx, 0
;
; Go find a block in the free list which is large enough.
;
; Uses the following algorithm:
;
;
cmp cs:FreeSpace, 0 ;See if no free space.
jz MemoryFull
mov ds, cs:FreeSpace
mov ax, ds ;In case first block is it.
FindBlk: cmp cx, dsptr.blksize ;See if blk is large enuf.
jbe FoundBlk ;Go for it!
mov ax, dsptr.freefwdptr ;Get ptr to next free block.
mov ds, ax ;Set up pointer.
or ax, ax ;See if NIL
jnz FindBlk ;Repeat until NIL.
;
; If we drop down here, we've got some big problems.
;
MemoryFull: stc
pop ds
pop si
pop ax
mov es, cs:StartOfHeap ;In case they use this ptr
mov di, 8 ; anyway.
ret
;
; When we come down here, we've found a block large enough to satisfy the
; current memory request. If necessary, split the block up into two
; pieces and return the unused half back to the free pool.
;
FoundBlk: jne SplitBlock
;
;
;
;***************************************************************************
; Exact fit, remove this guy from the free list and go for it!
;***************************************************************************
;
; There are four cases to deal with if this is an exact fit:
;
; 1) The block we're allocating is the first block in the free list.
; In this case, FreeSpace points at this block and the freebwdptr
; entry is NIL.
;
; 2) The block we're allocating is neither the first or last in the
; free list.
;
; 3) The block we're allocating is the last block in the free list.
; In this case, the freefwdptr will be NIL.
;
; 4) The block is both the first and last (i.e., only) block in the
; the free list.
;
; At this point, DS points at the block we're going to allocate.
;
mov ax, dsptr.freefwdptr ;Pointer to next free block.
cmp dsptr.freebwdptr, NIL ;First item in list?
jnz NotFirst
;
; Case (1) and (4) drop down here.
;
; If this is the first free block in the free link list, point FreeSpace
; beyond this guy rather than going through the usual linked list stuff.
;
; AX contains a pointer to the next free block (after this one) if it exists.
; DS points at the current free block.
;
; Since we are removing the first free block, we need to update the FreeSpace
; pointer so that it points at the next free block in the free block list.
;
mov cs:FreeSpace, ax ;Note: AX may be NIL if case (4).
;
; See if there is another block after this one. If not (case 4) then jump
; off to FixThisBlk.
;
or ax, ax ;Is there another free blk?
jz FixThisBlk ;If not, don't patch next adrs.
;
; Case (1), only, do